package blasthouse.objects;

import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;

import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;

import blasthouse.characters.Mob;
import blasthouse.states.GamePlayState;
import blasthouse.states.Toolbox;

public class CollisionWaypoint {
	private Vector<CollisionWaypoint> brothers = new Vector<CollisionWaypoint>();
	private Vector<CollisionWaypoint> children = new Vector<CollisionWaypoint>();
	private Vector<UpdatingGameElement> list = new Vector<UpdatingGameElement>();
	private CollisionWaypoint parent = null;
	private int tier = 0, X, Y;
	
	
	public int getX(){ return this.X; }
	public void setX(int x){ this.X = x; }
	
	public int getY(){ return this.Y; }
	public void setY(int y){ this.Y = y; }
	
	public void setPosition(int x, int y){
		this.X = x;
		this.Y = y;
	}
	
	public Vector2f getPosition(){ return new Vector2f( this.X, this.Y); }
	
	public void addChildWaypoint(CollisionWaypoint wp){		
		if( wp.parent != null & wp.parent != this ){ wp.parent.children.remove(wp); }
		wp.parent = this;
		if( !this.children.contains(wp) ){ this.children.add(wp); }
	}
	
	public void removeChildWaypoint(CollisionWaypoint wp){ 
		this.children.remove(wp);
		wp.parent = null;
	}
	/**
	 * @return the children, Waypoints on the lower tier
	 */
	public Vector<CollisionWaypoint> getChildren() {
		return children;
	}
	/**
	 * @return the brothers, Waypoints on the same tier
	 */
	public Vector<CollisionWaypoint> getBrothers() {
		return brothers;
	}
	/**
	 * @param brothers the brothers to set, used primarily to copy Waypoints
	 */
	public void setBrothers(Vector<CollisionWaypoint> brothers) {
		this.brothers = brothers;
	}
	/**
	 * @return the list of objects the Waypoint is tracking
	 */
	public Vector<UpdatingGameElement> getList() {
		return list;
	}
	/**
	 * @param list the list to set, primarily used for copying
	 */
	public void setList(Vector<UpdatingGameElement> list) {
		this.list = list;
	}
	/**
	 * @return the parent Waypoint of this Waypoint
	 */
	public CollisionWaypoint getParent() {
		return parent;
	}
	/**
	 * @param parent the parent to set for this Waypoint
	 */
	public void setParent(CollisionWaypoint wp) {
		if( this.parent != null && this.parent != wp ){ this.parent.removeChildWaypoint(this); }
		this.parent = wp;
		if( !wp.children.contains(this) ){ wp.children.add(this); }
	}	
	
	/**
	 * @param waypoint the brother node to add to the list of brothers
	 */
	public void addBrotherNode(CollisionWaypoint wp){
		if (this.brothers.contains(wp)){ return; }
		
		this.brothers.add(wp);
	}
	
	/**
	 * @param item the item nearby to keep track of
	 */
	public void addObject(UpdatingGameElement item){
		this.list.add(item);		
	}
	
	/** 
	 * @param item the item to remove from this Waypoint's tracking
	 */
	public void removeObject(UpdatingGameElement item){
		this.list.remove(item);
	}
	
	public void populateList( int minWaypointDistance ){
		int displace = minWaypointDistance /2 ;
		Rectangle area = new Rectangle( this.getX() - displace, this.getY() - displace, 
				minWaypointDistance, minWaypointDistance );
		
		for (UpdatingGameElement e : GamePlayState.GameObjects) {			
			if ( area.contains( e.getCenter().x, e.getCenter().y ) ){
				this.addObject(e);
			}
		}
		for (UpdatingGameElement a : GamePlayState.Actors) {			
			if ( area.contains( a.getCenter().x, a.getCenter().y ) ){
				this.addObject(a);
			}
		}
	}	
	
	public void populateChildren( int minWaypointDistance) {
		float range =  (2 * minWaypointDistance) * (float)Math.sqrt( 2 ) + 1;
		
		for ( CollisionWaypoint cwp : GamePlayState.waypointGrid ) {
			if( Toolbox.distanceBetween( cwp.getPosition(), this.getPosition() ) <= range ){
				this.addChildWaypoint(cwp);
			}
		}
	}
	
	public void populateBrothers( int minWaypointDistance ) {
		for (CollisionWaypoint cwp : GamePlayState.waypointGrid) {
			if( !cwp.equals(this) ){
				if (cwp.getX() > this.getX() - (minWaypointDistance+1) && cwp.getX() < this.getX() + (minWaypointDistance+1)){
					if (cwp.getY() > this.getY() - (minWaypointDistance+1) && cwp.getY() < this.getY() + (minWaypointDistance+1)){
						this.addBrotherNode(cwp);
					}
				}			
			}
		}
	}
	
	public int calculateTier(){
		Vector<Integer> results = new Vector<Integer>();
		for( CollisionWaypoint w : this.children ){
			results.add(w.calculateTier());			
		}
		
		if( results.isEmpty() ){ results.add(new Integer(0)); }
		
		this.tier = Collections.max(results) + 1;
		return Collections.max(results) + 1;
	}
}